#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "myMenu.h"

#define TAB_STRING "    "
#define QUIT_MENU_PROMPT_STRING "0. Quit menu.\n"
#define GO_BACK_PROMPT_STRING "0. Go back upper menu.\n"
#define ROOT_DEPTH 0
#define MAX_DPETH_LIMIT 100

#define max(x, y) ((x) > (y) ? (x) : (y))


unsigned int find_max_length(menu_node_t *node_list, unsigned int list_length)
{
    unsigned int i;
    unsigned int max_length = 0;

    for (i = 0; i < list_length; i++) {
        if (max_length < strlen(node_list[i].prompt)) {
            max_length = strlen(node_list[i].prompt);
        }
    }

    return max_length;
}


void print_chars(char character, unsigned int count)
{
    char buffer[count + 2];
    memset(buffer, character, count);
    
    buffer[count] = '\n';
    buffer[count + 1] = '\0';
    printf(buffer);
}


void show_menu_items(menu_node_t *menu, bool is_root)
{
    unsigned int i;
    unsigned max_prompt_length;
    menu_node_t *sub_node_list = menu->node_value.sub_node_list;

    max_prompt_length = find_max_length(menu, menu->sub_node_number) + 8;

    if (is_root) {
        max_prompt_length = max(max_prompt_length, strlen(QUIT_MENU_PROMPT_STRING)) + 8;
        print_chars('*', max_prompt_length);
        printf(TAB_STRING QUIT_MENU_PROMPT_STRING);
    } else {
        max_prompt_length = max(max_prompt_length, strlen(GO_BACK_PROMPT_STRING)) + 8;
        print_chars('*', max_prompt_length);
        printf(TAB_STRING GO_BACK_PROMPT_STRING);
    }

    for (i = 0; i < menu->sub_node_number; i++) {
        printf(TAB_STRING "%d. %s\n", i + 1, sub_node_list[i].prompt);
    }
    print_chars('*', max_prompt_length);
}


return_value_enum_t show_menu_with_depth_limit(menu_node_t *menu_root, unsigned int depth)
{
    int select = 0;
    menu_node_t *select_node = NULL;
    return_value_enum_t return_value;

    if (depth >= MAX_DPETH_LIMIT) {
        return WARRING_RETURN;
    }

    switch(menu_root->node_type)
    {
        case ITEM_TYPE:
            menu_root->node_value.func();
            return_value = OK_RETURN;
            break;
        case FOLDER_TYPE:
            while(1) {
                show_menu_items(menu_root, depth == ROOT_DEPTH);
                scanf("%d", &select);
                if (select == 0) {
                    return OK_RETURN;
                }
                if (select > menu_root->sub_node_number) {
                    fprintf(stderr, "WARRNING: Wrong select number %d! The select number should in range [0, %d].\n", select, menu_root->sub_node_number);
                    continue;
                }
                select_node = &(menu_root->node_value.sub_node_list[select - 1]);
                return_value = show_menu_with_depth_limit(select_node, depth + 1);
                if (return_value != OK_RETURN) {
                    return return_value;
                }
            }
            break;
        default:
            fprintf(stderr, "FATAL: Wrong `node_type` %d!\n", menu_root->node_type);
            return FATAL_ERROR_RETURN;
    }

    return return_value;
}


return_value_enum_t ShowMenu(menu_node_t *menu_root)
{
    return show_menu_with_depth_limit(menu_root, ROOT_DEPTH);
}